package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/PuerkitoBio/goquery"
)

type TiebaSigner struct {
	headers map[string]string
}

func loadCookieFromConfig() string {
	file, err := os.Open("cookie.json")
	if err != nil {
		log.Fatalf("Failed to open cookie.json: %v", err)
	}
	defer file.Close()

	content, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatalf("Failed to read cookie.json: %v", err)
	}

	var data map[string]string
	if err := json.Unmarshal(content, &data); err != nil {
		log.Fatalf("Failed to parse cookie.json: %v", err)
	}

	return data["baidu_cookie"]
}

func NewTiebaSigner() *TiebaSigner {
	return &TiebaSigner{
		headers: map[string]string{
			"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0",
			"Cookie":     loadCookieFromConfig(),
		},
	}
}

func (ts *TiebaSigner) fetchURL(url string) (string, error) {
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return "", err
	}

	for key, value := range ts.headers {
		req.Header.Set(key, value)
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

func (ts *TiebaSigner) getLikeList() {
	log.Println("开始获取账号关注的贴吧列表")
	url := "https://tieba.baidu.com/f/like/mylike"
	htmlStr, err := ts.fetchURL(url)
	if err != nil {
		log.Fatalf("Failed to fetch URL: %v", err)
	}

	re := regexp.MustCompile(`<a href="/f/like/mylike\?&pn=(.*?)">`)
	pnList := re.FindAllStringSubmatch(htmlStr, -1)
	if len(pnList) == 0 {
		log.Println("cookie为空或者已过期, 请在cookie.json文件中填写正确的cookie后重试")
		return
	}

	pageNum, err := strconv.Atoi(pnList[len(pnList)-1][1])
	if err != nil {
		log.Fatalf("Failed to parse page number: %v", err)
	}

	var wg sync.WaitGroup
	for i := 1; i <= pageNum; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			pageURL := fmt.Sprintf("https://tieba.baidu.com/f/like/mylike?&pn=%d", i)
			htmlStr, err := ts.fetchURL(pageURL)
			if err != nil {
				log.Printf("Failed to fetch page %d: %v", i, err)
				return
			}

			doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlStr))
			if err != nil {
				log.Printf("Failed to parse HTML for page %d: %v", i, err)
				return
			}

			doc.Find("tr").Each(func(index int, item *goquery.Selection) {
				if index == 0 {
					return
				}
				name := item.Find("a").AttrOr("title", "")
				tbs := item.Find("span").AttrOr("tbs", "")
				ts.sign(name, tbs)
			})
		}(i)
	}
	wg.Wait()
	log.Println("执行完毕")
}

func (ts *TiebaSigner) sign(kw, tbs string) {
	signURL := "https://tieba.baidu.com/sign/add"
	data := fmt.Sprintf("ie=utf-8&kw=%s&tbs=%s", kw, tbs)

	client := &http.Client{}
	req, err := http.NewRequest("POST", signURL, strings.NewReader(data))
	if err != nil {
		log.Printf("Failed to create request for %s: %v", kw, err)
		return
	}

	for key, value := range ts.headers {
		req.Header.Set(key, value)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err := client.Do(req)
	if err != nil {
		log.Printf("Failed to sign %s: %v", kw, err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Failed to read response for %s: %v", kw, err)
		return
	}

	var jsonData map[string]interface{}
	if err := json.Unmarshal(body, &jsonData); err != nil {
		log.Printf("Failed to parse response for %s: %v", kw, err)
		return
	}

	if errorVal, ok := jsonData["error"].(float64); ok && errorVal == 0 {
		data := jsonData["data"].(map[string]interface{})
		rank := data["finfo"].(map[string]interface{})["current_rank_info"].(map[string]interface{})["sign_count"]
		num := data["uinfo"].(map[string]interface{})["total_sign_num"]
		log.Printf("%s吧 签到成功✔！, 签到排名：%v, 已签到 %v天", kw, rank, num)
	} else {
		log.Printf("%s吧 签到失败✘, %v", kw, jsonData["error"])
	}
}

func main() {
	signer := NewTiebaSigner()
	signer.getLikeList()
}